qdoc.cpp/* \file qdoc.cpp
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <string>
using namespace std;
#include "strtoken.h"
const int MAX_FILES = 32;
//! documents Quartus Verilog projects
class qdoc {
public:
qdoc() { };
~qdoc() { };
void read_qsf(FILE *in);
void read_cfg(FILE *in, FILE *out);
void parse_insert(char *str, FILE *out);
void print();
void verilog_contents(FILE *out);
void quartus_contents(FILE *out);
void swap_toplevel();
void verilog_print(FILE *out, string filename);
void quartus_print(FILE *out, string suffix);
string projname;
string family,device,date,quartus_version;
string toplevel;
string verilog_file[MAX_FILES];
string quartus_file[MAX_FILES];
int nfiles, nqfiles;
};
void transcribe(FILE *in, FILE *out);
int main(int argc, char *argv[])
{
qdoc doc;
FILE *in, *out;
errno_t nerr;
if (argc<2) {
cout << "usage: qdoc projname [config_file]\n";
cout << "default config_file is \"qdoc.cfg.html\"\n";
return EXIT_FAILURE;
}
// open project qsf file
doc.projname = argv[1];
string filename = doc.projname + ".qsf";
nerr = fopen_s(&in,filename.c_str(),"r");
if (nerr) {
cout << "file: " << filename << " not found\n";
return EXIT_FAILURE;
}
doc.read_qsf(in);
doc.swap_toplevel();
fclose(in);
// open output configuration file
filename = (argc>2? argv[2]: "qdoc.cfg.html");
nerr = fopen_s(&in,filename.c_str(),"r");
if (nerr) {
cout << "file: " << filename << " not found\n";
return EXIT_FAILURE;
}
// open output file
filename = doc.projname + ".html";
nerr = fopen_s(&out,filename.c_str(),"w");
if (nerr) {
cout << "error opening " << filename << endl;
}
doc.read_cfg(in, out);
fclose(in);
fclose(out);
doc.print();
return EXIT_SUCCESS;
}
void qdoc::read_qsf(FILE *in)
{
char buf[512];
char *inp, *token;
bool done = false;
int lines = 0;
nfiles = 0;
while (!done) {
fgets(buf,511,in);
if (feof(in)) return;
lines++;
strtrm(buf,'\n'); // terminate at newline character
strtrm(buf,'#'); // terminate at comment character
inp = buf;
string tok;
int state = 0;
while ((token=strtoken(inp,' '))!=0) {
tok = token;
if (state==0) {
if (tok.compare("set_global_assignment")!=0) break;
state = 1;
}
else if (state==1) {
if (tok.compare("-name")!=0) break;
state = 2;
}
else if (state==2) {
strqtrm(inp,' ');
if (!inp) break;
if (tok.compare("FAMILY")==0) family = inp;
else if (tok.compare("DEVICE")==0) device = inp;
else if (tok.compare("TOP_LEVEL_ENTITY")==0) toplevel = inp;
else if (tok.compare("PROJECT_CREATION_TIME_DATE")==0)
date = inp;
else if (tok.compare("LAST_QUARTUS_VERSION")==0)
quartus_version = inp;
else if (tok.compare("VERILOG_FILE")==0)
verilog_file[nfiles++] = inp;
state = 0;
break;
}
}
}
}
void qdoc::swap_toplevel() {
string filename = toplevel + ".v";
int found = -1;
for (int i=0; i<nfiles; i++) {
if (filename.compare(verilog_file[i])==0) {
found = i;
break;
}
}
if (found) {
string tmp = verilog_file[0];
verilog_file[0] = verilog_file[found];
verilog_file[found] = tmp;
}
}
void qdoc::print() {
cout << "Family: " << family << endl;
cout << "Device: " << device << endl;
cout << "Quartus "<< quartus_version << endl;
cout << "date " << date << endl;
cout << "top level entity " << toplevel << endl;
if (nfiles) cout << nfiles << " verilog files\n";
if (nqfiles) cout << nqfiles << " quartus files\n";
}
void qdoc::verilog_contents(FILE *out)
{
for (int i=0; i<nfiles; i++) {
fputs("<a href=\"#",out);
fputs(verilog_file[i].c_str(),out);
fputs("\">",out);
fputs(verilog_file[i].c_str(),out);
fputs("</a><br>\n",out);
}
}
void qdoc::verilog_print(FILE *out, string filename)
{
FILE *in;
errno_t nerr = fopen_s(&in,filename.c_str(),"r");
if (nerr) {
cout << "file not found: " << filename << endl;
return;
}
fputs("<a name=\"",out);
fputs(filename.c_str(),out);
fputs("\">\n\n",out);
fputs("<h3><code>",out);
fputs(filename.c_str(),out);
fputs("</code></h3>\n",out);
transcribe(in,out);
fclose(in);
}
void qdoc::read_cfg(FILE *in, FILE *out)
{
char buf[512];
char *inp, *next, *html;
bool done = false;
nqfiles = 0;
/*
* Go through input file, line by line
*/
while (!done) {
fgets(buf,511,in);
if (feof(in)) break;
next = buf;
/*
* parse current line
*/
while (next) {
/*
* search for '<', and copy prior text to
* output stream
*/
inp = next;
next = strqtrm(inp,'<');
if (*inp) fputs(inp,out);
/*
* next points to character after '<' (if '<'
* was found).
*/
if (next) {
/*
* isolate (in html) text up to the character '>'
*/
html = next;
next = strqtrm(html,'>');
/*
* check for known codes
*/
string token = html;
char *value = strqtrm(html,' ');
if (token.substr(0,7).compare("include")==0) {
quartus_file[nqfiles++] = value;
//cout << "quartus_file: " << quartus_file[nqfiles-1] << endl;
continue; // go to next line
}
else if (token.substr(0,6).compare("insert")==0) {
parse_insert(value,out);
}
/*
* otherwise just echo the html code
*/
else fprintf(out,"<%s>",token.c_str());
}
}
}
}
void insert_date(FILE *out)
{
char buf[32];
time_t ltime;
errno_t nerr;
time( <ime );
nerr = ctime_s(buf,30,<ime);
int nchar = strlen(buf);
buf[nchar-1] = 0;
fputs(buf,out);
}
void qdoc::parse_insert(char *str, FILE *out)
{
string tok = str; //strtoken(str,' ');
if (tok.compare("projname")==0) fputs(projname.c_str(),out);
else if (tok.compare("date")==0) insert_date(out);
else if (tok.compare("verilog_contents")==0) verilog_contents(out);
else if (tok.compare("quartus_contents")==0) quartus_contents(out);
else if (tok.compare("verilog")==0) {
for (int i=0; i<nfiles; i++) verilog_print(out,verilog_file[i]);
}
else if (tok.compare("quartus")==0) {
for (int i=0; i<nqfiles; i++) quartus_print(out,quartus_file[i]);
}
else cout << "insert: " << tok << endl;
}
void qdoc::quartus_contents(FILE *out)
{
for (int i=0; i<nqfiles; i++) {
fputs("<a href=\"#",out);
fputs(quartus_file[i].c_str(),out);
fputs("\">",out);
fputs(quartus_file[i].c_str(),out);
fputs("</a><br>\n",out);
}
}
void qdoc::quartus_print(FILE *out, string suffix)
{
FILE *in;
string filename = projname + "." + suffix;
errno_t nerr = fopen_s(&in,filename.c_str(),"r");
if (nerr) {
cout << "file not found: " << filename << endl;
return;
}
// anchor definition
fputs("<a name=\"",out);
fputs(suffix.c_str(),out);
fputs("\">\n\n",out);
// section header
fputs("<h3><code>",out);
fputs(suffix.c_str(),out);
fputs("</code></h3>\n",out);
transcribe(in,out);
fclose(in);
}
void transcribe(FILE *in, FILE *out)
{
char ch;
bool done = false;
fputs("<p><pre>\n",out);
while (!done) {
ch = (char) fgetc(in);
if (feof(in)) break;
if (ch=='<') fputs("<",out);
else if (ch=='>') fputs(">",out);
else if (ch=='&') fputs("&",out);
else if (ch=='\t') fputs(" ",out);
else fputc(ch,out);
}
fputs("</pre>\n",out);
fclose(in);
}
/*
set_global_assignment -name FAMILY "Cyclone II"
set_global_assignment -name DEVICE EP2C35F672C6
set_global_assignment -name TOP_LEVEL_ENTITY de2lab1
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 6.0
set_global_assignment -name PROJECT_CREATION_TIME_DATE "15:49:53 JANUARY 16, 2007"
set_global_assignment -name LAST_QUARTUS_VERSION 6.0
set_global_assignment -name VERILOG_FILE hex_7seg.v
*/
Maintained by John Loomis, updated Thu Jan 18 11:04:13 2007